package ua.lviv.franko.solvers.stressanalysis.twoDimention.combined;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

import ua.lviv.franko.integration.ConstantFunction1D;
import ua.lviv.franko.integration.ConstantFunction2D;
import ua.lviv.franko.integration.FunctionWithoutDerivatives1D;
import ua.lviv.franko.integration.Gauss2D;
import ua.lviv.franko.integration.IFunction1D;
import ua.lviv.franko.integration.IFunction2D;
import ua.lviv.franko.solvers.stressanalysis.oneDimention.AbstractElement1D;
import ua.lviv.franko.solvers.stressanalysis.oneDimention.BubbleElement;
import ua.lviv.franko.solvers.stressanalysis.oneDimention.EquationParameters;
import ua.lviv.franko.solvers.stressanalysis.oneDimention.TimoshenkoMembraneSolver;
import ua.lviv.franko.solvers.stressanalysis.twoDimention.FEMResultStress;
import ua.lviv.franko.solvers.stressanalysis.twoDimention.Solver;
import ua.lviv.franko.solvers.stressanalysis.twoDimention.fem.AbstractStressElement;
import ua.lviv.franko.solvers.stressanalysis.twoDimention.fem.LinearRectangularElement;
import ua.lviv.franko.solvers.stressanalysis.twoDimention.savestructures.bounderyconditions.BounderyConditionLinear;
import ua.lviv.franko.solvers.stressanalysis.twoDimention.savestructures.bounderyconditions.BounderyConditionStressInterface;
import ua.lviv.franko.solvers.stressanalysis.twoDimention.savestructures.bounderyconditions.BounderyConditionType;
import ua.lviv.franko.triangulation.SaveStructures.Node;
import ua.lviv.franko.triangulation.SaveStructures.NodePair;
import ua.lviv.franko.triangulation.SaveStructures.Rectangle;
import ua.lviv.franko.visualisation.NewOkCancelDialog;

public class Test {
	public static final double	EPS	= 0.00000000000000000001;

	public static void main(String[] args) {
		double ax = -0.0, bx = 1.0, ay = -0.0, by = 1.0;

		int n = 5, m = 5;

		double hx = (bx - ax) / (double) n, hy = (by - ay) / (double) m;

		// вузли+функції:
		// for (int i = 0; i <= m; i++) {
		// for (int j = 0; j <= n; j++) {
		// Node p = new Node(ax + j * hx, ay + i * hy, false, i * n + j);
		// System.out.println(p.x + "\t" + p.y);
		// // if ((i==0)||(j==0)) {
		// // p.IsOnBoundery=true;
		// // }
		// // nodeList.add(p);
		// }
		// }
		// double k1 = 1;
		// double k2 = 0.5;
		// double k3 = 0.25;
		double v = 0.6;
		double e = 0.6;

		IFunction2D f1 = new ConstantFunction2D(10.0);
		IFunction2D f2 = new ConstantFunction2D(10.0);
		List<AbstractStressElement> elems = new ArrayList<AbstractStressElement>();
		Set<Node> tmpNodesSet = new HashSet<Node>();

		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {
				// if(i==m-1 && j==n-1) continue;
				Rectangle r = new Rectangle();
				r.A = new Node(ax + j * hx, ay, false, i * (n + 1) + j);
				r.B = new Node(ax + (j + 1) * hx, ay, false, i * (n + 1) + j + 1);
				r.C = new Node(ax + (j + 1) * hx, ay + hy, false, (i + 1) * (n + 1) + j + 1);
				r.D = new Node(ax + j * hx, ay + hy, false, (i + 1) * (n + 1) + j);
				tmpNodesSet.add(r.A);
				tmpNodesSet.add(r.B);
				tmpNodesSet.add(r.C);
				tmpNodesSet.add(r.D);
				// if ((i==0)||(i==n)) {
				// r.A.IsOnBoundery=true;
				// }

				// LinearRectangularElement elem = new LinearRectangularElement(r.A, r.B, r.C, r.D, k1, k2, k3, f1, f2);
				LinearRectangularElement elem = new LinearRectangularElement(r.A, r.B, r.C, r.D, e, v, f1, f2);
				// EnrichedLinearRectangularElement elem = new
				// EnrichedLinearRectangularElement(i*(n+1)+j, i*(n+1)+j+1,
				// (i+1)*(n+1)+j+1, (i+1)*(n+1)+j, r.A, r.B, r.C, r.D,eParams,
				// 3, 3);
				elems.add(elem);
			}
			ay += hy;
		}
		ay = -0.5;
		List<Node> nodes = new ArrayList<Node>();
		nodes.addAll(tmpNodesSet);
		Collections.sort(nodes);
		List<BounderyConditionStressInterface> bounderies = new ArrayList<BounderyConditionStressInterface>();
		List<NodePair> leftNodePairs = new ArrayList<NodePair>();
		List<NodePair> rightNodePairs = new ArrayList<NodePair>();
		List<NodePair> topNodePairs = new ArrayList<NodePair>();
		List<NodePair> bottomNodePairs = new ArrayList<NodePair>();
		for (AbstractStressElement element : elems) {
			List<Integer> positions = element.getPos();
			Node A = nodes.get(positions.get(0));
			Node B = nodes.get(positions.get(1));
			Node C = nodes.get(positions.get(2));
			Node D = nodes.get(positions.get(3));
			// left
			List<Node> tmpNodes = new ArrayList<Node>();
			if (Math.abs(A.x - ax) < EPS) {
				tmpNodes.add(A);
			}
			if (Math.abs(B.x - ax) < EPS) {
				tmpNodes.add(B);
			}
			if (Math.abs(C.x - ax) < EPS) {
				tmpNodes.add(C);
			}
			if (Math.abs(D.x - ax) < EPS) {
				tmpNodes.add(D);
			}

			if (tmpNodes.size() == 2) {
				leftNodePairs.add(new NodePair(tmpNodes.get(0), tmpNodes.get(1)));
			}

			// right
			tmpNodes.clear();
			if (Math.abs(A.x - bx) < EPS) {
				tmpNodes.add(A);
			}
			if (Math.abs(B.x - bx) < EPS) {
				tmpNodes.add(B);
			}
			if (Math.abs(C.x - bx) < EPS) {
				tmpNodes.add(C);
			}
			if (Math.abs(D.x - bx) < EPS) {
				tmpNodes.add(D);
			}

			if (tmpNodes.size() == 2) {
				rightNodePairs.add(new NodePair(tmpNodes.get(0), tmpNodes.get(1)));
			}

			// top
			tmpNodes.clear();
			if (Math.abs(A.y - by) < EPS) {
				tmpNodes.add(A);
			}
			if (Math.abs(B.y - by) < EPS) {
				tmpNodes.add(B);
			}
			if (Math.abs(C.y - by) < EPS) {
				tmpNodes.add(C);
			}
			if (Math.abs(D.y - by) < EPS) {
				tmpNodes.add(D);
			}

			if (tmpNodes.size() == 2) {
				topNodePairs.add(new NodePair(tmpNodes.get(0), tmpNodes.get(1)));
			}

			// bottom
			tmpNodes.clear();
			if (Math.abs(A.y - ay) < EPS) {
				tmpNodes.add(A);
			}
			if (Math.abs(B.y - ay) < EPS) {
				tmpNodes.add(B);
			}
			if (Math.abs(C.y - ay) < EPS) {
				tmpNodes.add(C);
			}
			if (Math.abs(D.y - ay) < EPS) {
				tmpNodes.add(D);
			}

			if (tmpNodes.size() == 2) {
				bottomNodePairs.add(new NodePair(tmpNodes.get(0), tmpNodes.get(1)));
			}
		}
		Gauss2D gauss2d = new Gauss2D(7);

		bounderies.add(new BounderyConditionLinear(BounderyConditionType.DIRIHLET_TYPE, new ConstantFunction2D(0.0), new ConstantFunction2D(0.0), leftNodePairs, gauss2d));

		bounderies.add(new BounderyConditionLinear(BounderyConditionType.DIRIHLET_TYPE, new ConstantFunction2D(0.0), new ConstantFunction2D(0.0), rightNodePairs, gauss2d));

		Solver s = new Solver((n + 1) * (m + 1), elems, bounderies);
		s.generate();
		double[] res = s.solve();
		
		List<AbstractStressElement> nearBounderyElements = new ArrayList<AbstractStressElement>();
		for (AbstractStressElement abstractStressElement : elems) {
			List<Integer> nodeNumbers = abstractStressElement.getNodesNumbers();
			for (Integer index : nodeNumbers) {
				if (Math.abs(nodes.get(index).y - by) < EPS) {
					nearBounderyElements.add(abstractStressElement);
					break;
				}
			}
		}
		
		final FEMResultStress re = new FEMResultStress(res, nearBounderyElements);
		
		IFunction1D k1 = new ConstantFunction1D(1.0);
		IFunction1D a1 = new ConstantFunction1D(1.0);
		IFunction1D sigma11Plus = new ConstantFunction1D(0.0);
		IFunction1D sigma13Minus = new ConstantFunction1D(0.0);
		IFunction1D sigma11Minus = new ConstantFunction1D(0.0);
		IFunction1D sigma33Minus = new ConstantFunction1D(0.0);
		IFunction1D sigma33Plus = new FunctionWithoutDerivatives1D() {
			
			@Override
			public double calculate(double x) {
				return re.getSigma11().calculate(x, 1);
			}
		};
		IFunction1D sigma13Plus = new FunctionWithoutDerivatives1D() {
			
			@Override
			public double calculate(double x) {
				return re.getSigma12().calculate(x, 1);
			}
		};
		double h = 0.01;

		EquationParameters eqP = new EquationParameters(a1, k1, e, v, h, f1, f2, sigma13Plus, sigma13Minus, sigma11Plus, sigma11Minus, sigma33Plus, sigma33Minus);
		double a = 0.0;
		double b = 1.0;
		int n1 = 15;
		double hStep = (b - a) / (double) n1;
		ArrayList<AbstractElement1D> elements = new ArrayList<AbstractElement1D>();
		int i = 0;
		for (i = 0; i < n1; i++) {
			// elements.add(new FEElementLinear(eqP, i, a + i * hStep, a + (i + 1) * hStep));
			elements.add(new BubbleElement(eqP, i, a + i * hStep, a + (i + 1) * hStep));
			// elements.add(new EnrichedLinearElement(eqP, elements.size() > 0 ? elements.get(elements.size() - 1).getNodesNumbers()
			// .get(elements.get(elements.size() - 1).getNodesNumbers().size() - 1) : 0, a + i * hStep, a + (i + 1) * hStep, 5, 2, new CubicSpline(), 2.5));
		}

		TimoshenkoMembraneSolver solver = new TimoshenkoMembraneSolver(elements);
		solver.generate();
		solver.setBothDirihlet(new double[] { 0.0, 0.0, 0.0 }, new double[] { 0.0, 0.0, 0.0 });
		double[] results = solver.solve();
		// for (int j = 0; j < res.length; j++) {
		// System.out.println(res[j]);
		// }

		XYSeries s1 = new XYSeries("result1", true, true);
		XYSeries s2 = new XYSeries("result2", true, true);
		XYSeries s3 = new XYSeries("result3", true, true);

		// for (int j = 0; j < elements.size() + 1; j++) {
		// s1.add(a + j * hStep, res[j * 3]);
		// s2.add(a + j * hStep, res[j * 3 + 1]);
		// s3.add(a + j * hStep, res[j * 3 + 2]);
		// }

		int NNN = 10;
		AbstractElement1D el = null;
		for (int j = 0; j < elements.size(); j++) {
			el = elements.get(j);
			double hhh = hStep / NNN;
			for (int k = 0; k < NNN; k++) {
				double[] tmp = el.calculate(a + hStep * j + k * hhh, results);
				s1.add(a + hStep * j + k * hhh, tmp[0]);
				s2.add(a + hStep * j + k * hhh, tmp[1]);
				s3.add(a + hStep * j + k * hhh, tmp[2]);
			}
		}
		double[] tmp = el.calculate(b, results);
		s1.add(b, tmp[0]);
		s2.add(b, tmp[1]);
		s3.add(b, tmp[2]);

		XYSeriesCollection col = new XYSeriesCollection();
		col.addSeries(s1);
		col.addSeries(s2);
		col.addSeries(s3);
		NewOkCancelDialog d = new NewOkCancelDialog(null, false, col);
		d.setLocationRelativeTo(null);
		d.setVisible(true);
	}
}
